#include "gtest/gtest.h"
#include "MockClock.h"

using namespace helper;
using namespace watch;

TEST(TickTest, testMock){
    MockClock tick; 

    ASSERT_EQ(0, tick.init());
    ASSERT_EQ(MockClock::FIRST_TICK, tick.now());
    ASSERT_EQ(MockClock::SECOND_TICK, tick.now());

    ASSERT_EQ(MockClock::FIRST_TICK, tick.now());
    ASSERT_EQ(MockClock::SECOND_TICK, tick.now());

    Timespan<MockClock::TimePoint> ts(MockClock::FIRST_TICK, MockClock::SECOND_TICK);
    ASSERT_EQ(MockClock::SECOND_TICK - MockClock::FIRST_TICK, 
        tick.diff(ts));
}

#include "helper/watch/StopWatch.h"
TEST(StopWatchSingleShotTest, testIf){
    StopWatchSingleShot<MockClock> swss;
    swss.enter();
    swss.exit();
    std::string expectTimespan = "startTs:10,endTs:100,elapse:90";
    ASSERT_EQ(expectTimespan, swss.toString());
}
TEST(StopWatchSingleShotTest, testStateError){
    StopWatchSingleShot<MockClock> swss;
    ASSERT_EQ(-1, swss.exit()); //case 1

    ASSERT_EQ(0, swss.enter()); 
    ASSERT_EQ(-1, swss.enter()); // case 2

    ASSERT_EQ(0, swss.exit());
    ASSERT_EQ(-1, swss.exit());  // case 3

    ASSERT_EQ(-1, swss.enter()); // case 4

    swss.reset();
    ASSERT_EQ(0, swss.enter());
    ASSERT_EQ(0, swss.exit()); // case 5
}

#include "helper/watch/Lap.h"

TEST(StopWatchSingleShotTest, testUseLap){
    StopWatchSingleShot<MockClock> swss;
    {
        Lap<void> lap(swss);
    }
    std::string expectTimespan = "startTs:10,endTs:100,elapse:90";
    ASSERT_EQ(expectTimespan, swss.toString());
}


TEST(StopWatchTest, testIf){
    StopWatch<MockClock> sw;
    {
        Lap<void> lap(sw);
    }
    {
        Lap<void> lap(sw);
    }
    {
        Lap<void> lap(sw);
    }
    std::string expectTimespan = "0>startTs:10,endTs:100,elapse:90;1>startTs:10,endTs:100,elapse:90;2>startTs:10,endTs:100,elapse:90;";
    ASSERT_EQ(expectTimespan, sw.toString());
}

TEST(StopWatchTest, testRepeat){
    StopWatch<MockClock> sw;
    ASSERT_EQ(0, sw.enter()); 
    ASSERT_EQ(0, sw.exit());   // normal case 

    ASSERT_EQ(0, sw.enter()); 
    ASSERT_EQ(0, sw.exit());   // normal case 

    ASSERT_EQ(0, sw.enter()); 
    ASSERT_EQ(0, sw.exit());   // normal case 

    std::string expectTimespan = "0>startTs:10,endTs:100,elapse:90;1>startTs:10,endTs:100,elapse:90;2>startTs:10,endTs:100,elapse:90;";
    ASSERT_EQ(expectTimespan, sw.toString());

}

TEST(StopWatchTest, testRepeatException){
    StopWatch<MockClock> sw;
    ASSERT_EQ(-1, sw.exit()); // case 1

    ASSERT_EQ(0, sw.enter()); //case 
    ASSERT_EQ(-1, sw.enter()); //case 2

    ASSERT_EQ(0, sw.exit());   // normal case 
    ASSERT_EQ(-1, sw.exit()); //case 3

    std::string expectTimespan = "0>startTs:10,endTs:100,elapse:90;";
    ASSERT_EQ(expectTimespan, sw.toString());
}

TEST(NamedStopWatchSingleShotTest, testIf){
    NamedStopWatchSingleShot<MockClock> nswss;
    ASSERT_EQ(0, nswss.enter("hello"));
    ASSERT_EQ(-1, nswss.exit("world"));
    ASSERT_EQ(0, nswss.exit("hello"));

    std::string expectTimespan = "hello>startTs:10,endTs:100,elapse:90";
    ASSERT_EQ(expectTimespan, nswss.toString());
}
TEST(NamedStopWatchSingleShotTest, testExceptState){
    NamedStopWatchSingleShot<MockClock> nswss;
    ASSERT_EQ(0, nswss.enter("hello"));
    ASSERT_EQ(-1, nswss.enter("hello")); //case  1
    ASSERT_EQ(0, nswss.exit("hello"));

    ASSERT_EQ(-1, nswss.enter("hello")); //case 2
    ASSERT_EQ(-1, nswss.exit("hello"));  //case 3

    std::string expectTimespan = "hello>startTs:10,endTs:100,elapse:90";
    ASSERT_EQ(expectTimespan, nswss.toString());
}

TEST(NamedStopWatchSingleShot, testLap){
    NamedStopWatchSingleShot<MockClock> nswss;
    {
        Lap<const std::string> lap("code-block", nswss);
    }
    std::string expectTimespan = "code-block>startTs:10,endTs:100,elapse:90";
    ASSERT_EQ(expectTimespan, nswss.toString());
}
TEST(NamedStopWatchSingleShot, testNamedLap){
    NamedStopWatchSingleShot<MockClock> nswss;
    {
        NamedLap lap("code-block", nswss);
    }
    std::string expectTimespan = "code-block>startTs:10,endTs:100,elapse:90";
    ASSERT_EQ(expectTimespan, nswss.toString());
}

TEST(NamedStopWatchTest, testIf){
    NamedStopWatch<MockClock> nsw;
    {
        NamedLap ("world", nsw);
    }
    {
        NamedLap ("hello", nsw);
    }
    std::string expectTimespan = "hello>startTs:10,endTs:100,elapse:90;world>startTs:10,endTs:100,elapse:90;";
    ASSERT_EQ(expectTimespan, nsw.toString());
}

#include "helper/watch/ChronoClock.h"
TEST(StopWatchSingleShotTest, testChoronClockSteadyClock){
	StopWatchSingleShot<ChronoClock<>> swss;
	//StopWatchSingleShot<ChronoClock<std::chrono::nanoseconds>> swss;
	{
		Lap<void> lap(swss);
		int sum = 0;
		for(long long  i = 0; i < 1000*1000; i++){
			sum += 100;
		}
	}
	std::cout << swss.toString() << std::endl;
}
TEST(StopWatchSingleShotTest, testChoronClockSystemClock){
	StopWatchSingleShot<ChronoClock<std::chrono::system_clock>> swss;
	{
		Lap<void> lap(swss);
		int sum = 0;
		for(long long  i = 0; i < 1000*1000; i++){
			sum += 100;
		}
	}
	std::cout << swss.toString() << std::endl;
}
